package com.gugee.tiktok.web.service;

import cn.hutool.core.date.DateUtil;
import com.gugee.common.web.util.ESUtil;
import com.gugee.tiktok.web.dto.*;
import com.gugee.tiktok.web.model.mysql.*;
import com.gugee.tiktok.web.repository.*;
import com.xiguaji.boot.toolkit.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class MyTiktokService {
    @Autowired
    TAwemeRecordRepository tAwemeRecordRepository;

    @Autowired
    AwemeRepository awemeRepository;

    @Autowired
    TBloggerRepository tBloggerRepository;

    @Autowired
    TBloggerRecordRepository tBloggerRecordRepository;

    @Autowired
    TGroupBloggerRepository tGroupBloggerRepository;

    @Autowired
    TGroupRepository tGroupRepository;

    @Autowired
    RestHighLevelClient client;

    @Autowired
    MTBloggerDataResponse.BloggerDataMapper bloggerDataMapper;;

    /**
     * 每个用户能添加的最大mytitoker数
     */
    @Value("${tiktok.mytitoker.num.max}")
    private int MY_TIKTOKER_MAX_COUNT;

    /**
     * 播主列表信息及统计信息(总数据)导出数据集的列名
     */
    private String[] EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME = new String[]{"Name","Username","GD index","Followers","Likes","Posts"};

    /**
     * 获取分组数据
     * @param userId
     */
    public List<GroupResponse> getGroupDataList(long userId){
        List<GroupResponse> groupData = new ArrayList<>();
        GroupResponse groupAll = new GroupResponse();
        groupAll.setName("All");
        groupAll.setId(0);
        groupAll.setBloggerResponses(getTBloggerData(userId));
        groupData.add(groupAll);
        List<TGroup> tGroups = tGroupRepository.findByUserIdOrderByGroupSortDesc(userId);
        List<GroupResponse> groupList = new ArrayList<>();
        tGroups.forEach( group -> {
            GroupResponse groupResponse = new GroupResponse();
            groupResponse.setId(group.getId());
            groupResponse.setName(group.getName());
            groupList.add(groupResponse);
        });

        groupList.forEach( g ->{
            List<TGroupBlogger> groupBloggers = getGroupBloggers(g.getId(),userId);
            List<BloggerResponse> bloggerResponses =  groupAll.getBloggerResponses();
            groupBloggers.forEach( gb ->{
                bloggerResponses.forEach(b ->{
                    if(gb.getUid() == b.getUid()){
                        g.getBloggerResponses().add(b);
                    }
                });
            });
        });

        groupData.addAll(groupList);
        return groupData;
    }

    /**
     * 添加或修改分类
     * @param group
     */
    public void addOrUpdateGroup(TGroup group){
        tGroupRepository.save(group);
    }

    public boolean checkGroupName(long userId,Long groupId,String groupName){
        if(null != groupId){
            return tGroupRepository.findByNameAndUserIdAndIdNot(groupName,userId,groupId).isPresent();
        }
        return tGroupRepository.findByNameAndUserId(groupName,userId).isPresent();
    }

    public TGroup findGroupById(long groupId){
        return tGroupRepository.findById(groupId).get();
    }

    public void deleteGroup(long groupId){
        tGroupBloggerRepository.deleteByGroupId(groupId);
        tGroupRepository.deleteById(groupId);
    }

    public void deleteBlogger(long userId,long uid){
        tBloggerRepository.deleteByUserIdAndUid(userId,uid);
        tGroupBloggerRepository.deleteByUserIdAndUid(userId,uid);
    }

    public void deleteGroupBlogger(long groupId,long uid){
        tGroupBloggerRepository.deleteByGroupIdAndUid(groupId,uid);
    }

    /**
     * 获取分组中的博主记录
     * @param groupId
     * @param uid
     * @return
     */
    public TGroupBlogger getGroupBlogger(long groupId,long uid){
        return tGroupBloggerRepository.findByGroupIdAndUid(groupId,uid);
    }

    public TGroupBlogger saveGroupBlogger(TGroupBlogger groupBlogger){
        return tGroupBloggerRepository.save(groupBlogger);
    }

    /**
     * 获取分组中的博主记录
     * @param userId
     * @param uid
     * @return
     */
    public TGroupBlogger getGroupBloggerByUserIdAndUid(long userId,long uid){
        return tGroupBloggerRepository.findByUserIdAndUid(userId,uid);
    }

    /**
     * 获取添加的博主记录
     * @param userId
     * @param uid
     * @return
     */
    public TBlogger getBlogger(long userId, long uid){
        return tBloggerRepository.findByUserIdAndUidOrderByBloggerSort(userId,uid);
    }

    /**
     * 保存或更新添加博主记录
     * @param blogger
     * @return
     */
    public TBlogger saveBlogger(TBlogger blogger){
        return tBloggerRepository.save(blogger);
    }

    /**
     * 获取用户添加的播主列表
     * @param userId
     * @return
     */
    public List<BloggerResponse> getTBloggerData(long userId){
        return tBloggerRepository.findByUserIdOrderByBloggerSortDesc(userId);
    }

    /**
     * 获取分组下的播主列表
     * @param groupId
     * @param userId
     * @return
     */
    public List<TGroupBlogger> getGroupBloggers(long groupId,long userId){
        return tGroupBloggerRepository.findByGroupIdAndUserIdOrderByBloggerSortDesc(groupId,userId);
    }

    public List<BloggerResponse> getTBloggerData(long userId,long groupId){
        return tGroupBloggerRepository.findByLeftJoinTBlogger(userId,groupId);
    }

    /**
     * 获取博主最后更新时间
     * @return
     */
    public Long getLastBloggerRecordTime(){
        return tBloggerRecordRepository.getLastUpdateTime();
    }


    /**
     * 获取组下的播主列表信息及统计信息
     * @param groupId
     * @param userId
     */
    public List<MTBloggerDataResponse> getBloggerListByGroup(long groupId,long userId){
        // 合计
        MTBloggerDataResponse bloggerDataCount = new MTBloggerDataResponse();

        List<BloggerResponse> bloggerResponses;

        if(0 == groupId){
            bloggerResponses = getTBloggerData(userId);
        }else {
            bloggerResponses = getTBloggerData(userId, groupId);
        }
        List<MTBloggerDataResponse> bloggerDataResponses = bloggerDataMapper.mapper(bloggerResponses);


        DayData todayDataCount = new DayData();
        DayData yesterdayDataCount = new DayData();
        bloggerDataCount.setTodayData(todayDataCount);
        bloggerDataCount.setYesterdayData(yesterdayDataCount);


        bloggerDataResponses.forEach( bloggerDataResponse -> {
            val todayBloggerRecordData = getTodayBloggerRecordData(bloggerDataResponse.getUid(), 1);
            DayData todayData = new DayData();

            if(todayBloggerRecordData.size() > 0){

                todayBloggerRecordData.forEach( tBloggerRecord -> {
                    todayData.setPostsGrowth(todayData.getPostsGrowth()+tBloggerRecord.getPostsGrowth());
                    todayData.setFollowerGrowth(todayData.getFollowerGrowth()+tBloggerRecord.getFollowerGrowth());
                    todayData.setLikeGrowth(todayData.getLikeGrowth() + tBloggerRecord.getLikeGrowth());
                    todayData.setReviewGrowth(todayData.getReviewGrowth()+tBloggerRecord.getReviewGrowth());
                    todayData.setShareGrowth(todayData.getShareGrowth()+tBloggerRecord.getShareGrowth());
                    todayData.setViewGrowth(todayData.getViewGrowth()+tBloggerRecord.getViewGrowth());
                });
                todayData.setNewPosts(getTodayBloggerAwemeCount(bloggerDataResponse.getUid()));
                todayDataCount.setPostsGrowth(todayDataCount.getPostsGrowth()+ todayData.getPostsGrowth());
                todayDataCount.setFollowerGrowth(todayDataCount.getFollowerGrowth()+ todayData.getFollowerGrowth());
                todayDataCount.setReviewGrowth(todayDataCount.getReviewGrowth()+ todayData.getReviewGrowth());
                todayDataCount.setViewGrowth(todayDataCount.getViewGrowth()+todayData.getViewGrowth());
                todayDataCount.setShareGrowth(todayDataCount.getShareGrowth()+todayData.getShareGrowth());
                todayDataCount.setLikeGrowth(todayDataCount.getLikeGrowth()+todayData.getLikeGrowth());
                todayDataCount.setNewPosts(todayDataCount.getNewPosts()+ todayData.getNewPosts());
            }
            bloggerDataResponse.setTodayData(todayData);

            val yesterdayBloggerRecordData = getYesterdayBloggerRecordData(bloggerDataResponse.getUid(), 1);
            DayData yesterdayData = new DayData();

            if(yesterdayBloggerRecordData.size() >0){
                yesterdayBloggerRecordData.forEach( tBloggerRecord -> {
                    yesterdayData.setPostsGrowth(yesterdayData.getPostsGrowth()+tBloggerRecord.getPostsGrowth());
                    yesterdayData.setFollowerGrowth(yesterdayData.getFollowerGrowth()+tBloggerRecord.getFollowerGrowth());
                    yesterdayData.setLikeGrowth(yesterdayData.getLikeGrowth() + tBloggerRecord.getLikeGrowth());
                    yesterdayData.setReviewGrowth(yesterdayData.getReviewGrowth()+tBloggerRecord.getReviewGrowth());
                    yesterdayData.setShareGrowth(yesterdayData.getShareGrowth()+tBloggerRecord.getShareGrowth());
                    yesterdayData.setViewGrowth(yesterdayData.getViewGrowth()+tBloggerRecord.getViewGrowth());
                });

                yesterdayData.setNewPosts(getYesterdayBloggerAwemeCount(bloggerDataResponse.getUid()));
                yesterdayDataCount.setPostsGrowth(yesterdayDataCount.getPostsGrowth() + yesterdayData.getPostsGrowth());
                yesterdayDataCount.setFollowerGrowth(yesterdayDataCount.getFollowerGrowth() + yesterdayData.getFollowerGrowth());
                yesterdayDataCount.setReviewGrowth(yesterdayDataCount.getReviewGrowth() + yesterdayData.getReviewGrowth());
                yesterdayDataCount.setViewGrowth(yesterdayDataCount.getViewGrowth() + yesterdayData.getViewGrowth());
                yesterdayDataCount.setShareGrowth(yesterdayDataCount.getShareGrowth() + yesterdayData.getShareGrowth());
                yesterdayDataCount.setLikeGrowth(yesterdayDataCount.getLikeGrowth() + yesterdayData.getLikeGrowth());
                yesterdayDataCount.setNewPosts(yesterdayDataCount.getNewPosts()+ yesterdayData.getNewPosts());
            }
            bloggerDataResponse.setYesterdayData(yesterdayData);
        });

        bloggerDataResponses.add(bloggerDataCount);

        return bloggerDataResponses;
    }


    /**
     * 获取当天的数据走趋
     * @param uid
     * @param hourInterval
     */
    public DayDataResponse getDayData(long uid, int hourInterval){
        DayDataResponse dayDataResponse = new DayDataResponse();
        List<TBloggerRecord> todayRecord = getTodayBloggerRecordData(uid,1);
        List<TBloggerRecord> yesterdayRecord = getYesterdayBloggerRecordData(uid,1);
        DayData todayData = new DayData();
        DayData yesterdayData = new DayData();

        if(todayRecord.size() > 0){
            todayRecord.forEach( tBloggerRecord -> {
                todayData.setPostsGrowth(todayData.getPostsGrowth()+tBloggerRecord.getPostsGrowth());
                todayData.setFollowerGrowth(todayData.getFollowerGrowth()+tBloggerRecord.getFollowerGrowth());
                todayData.setLikeGrowth(todayData.getLikeGrowth() + tBloggerRecord.getLikeGrowth());
                todayData.setReviewGrowth(todayData.getReviewGrowth()+tBloggerRecord.getReviewGrowth());
                todayData.setShareGrowth(todayData.getShareGrowth()+tBloggerRecord.getShareGrowth());
                todayData.setViewGrowth(todayData.getViewGrowth()+tBloggerRecord.getViewGrowth());
            });
            todayData.setNewPosts(getTodayBloggerAwemeCount(uid));
            dayDataResponse.setUpdateTime(todayRecord.get(todayRecord.size()-1).getUpdateTime());
            todayRecord.removeIf(d-> {
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(d.getRecordDate() * 1000l);
                return calendar.get(Calendar.HOUR_OF_DAY) % hourInterval != 0;
            });
            todayData.setRecordData(todayRecord);
        }

        if(yesterdayRecord.size() > 0){
            yesterdayRecord.forEach( tBloggerRecord -> {
                yesterdayData.setPostsGrowth(yesterdayData.getPostsGrowth()+tBloggerRecord.getPostsGrowth());
                yesterdayData.setFollowerGrowth(yesterdayData.getFollowerGrowth()+tBloggerRecord.getFollowerGrowth());
                yesterdayData.setLikeGrowth(yesterdayData.getLikeGrowth() + tBloggerRecord.getLikeGrowth());
                yesterdayData.setReviewGrowth(yesterdayData.getReviewGrowth()+tBloggerRecord.getReviewGrowth());
                yesterdayData.setShareGrowth(yesterdayData.getShareGrowth()+tBloggerRecord.getShareGrowth());
                yesterdayData.setViewGrowth(yesterdayData.getViewGrowth()+tBloggerRecord.getViewGrowth());
            });
            yesterdayData.setNewPosts(getYesterdayBloggerAwemeCount(uid));
            yesterdayRecord.removeIf(d-> {
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(d.getRecordDate() * 1000l);
                return calendar.get(Calendar.HOUR_OF_DAY) % hourInterval != 0;
            });
            yesterdayData.setRecordData(yesterdayRecord);
        }

        dayDataResponse.setTodayData(todayData);
        dayDataResponse.setYesterdayData(yesterdayData);
        return dayDataResponse;

    }

    public List<TAwemeRecord> getAwemeData(long awemeId, int hourInterval){
        return tAwemeRecordRepository.findByAwemeId(awemeId,hourInterval);
    }

    public List<TBloggerRecord> getTodayBloggerRecordData(long uid, int hourInterval){
        long begin = DateUtil.offsetHour(DateUtil.beginOfDay(new Date()),1).getTime()/1000;
        long end = DateUtil.offsetDay(DateUtil.beginOfDay(new Date()),1).getTime()/1000;

        return tBloggerRecordRepository.findByUid(uid,begin,end,hourInterval);
    }

    public List<TBloggerRecord> getYesterdayBloggerRecordData(long uid, int hourInterval){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH,-1);
        long begin = DateUtil.offsetHour(DateUtil.beginOfDay(calendar.getTime()),1).getTime()/1000;
        long end = DateUtil.offsetDay(DateUtil.beginOfDay(calendar.getTime()),1).getTime()/1000;
        return tBloggerRecordRepository.findByUid(uid,begin,end,hourInterval);
    }

    public int getTodayBloggerAwemeCount(long uid){
        long begin = DateUtil.beginOfDay(new Date()).getTime()/1000;
        long end = DateUtil.endOfDay(new Date()).getTime()/1000;
        return awemeRepository.countByOUidAndOCreateTimeBetween(uid,begin,end);
    }

    public int getYesterdayBloggerAwemeCount(long uid){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH,-1);
        long begin = DateUtil.beginOfDay(calendar.getTime()).getTime()/1000;
        long end = DateUtil.endOfDay(calendar.getTime()).getTime()/1000;
        return awemeRepository.countByOUidAndOCreateTimeBetween(uid,begin,end);
    }

    public List<SearchDataResponse> searchBloggerByES(String keyword, long userId) {
        SearchRequest searchRequest = new SearchRequest(ESUtil.BLOGGER_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        List<SearchDataResponse> searchDataResponses = new ArrayList<>();

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.should(QueryBuilders.matchQuery("uniqueId",keyword));
        boolQueryBuilder.should(QueryBuilders.matchQuery("nickName",keyword));
        boolQueryBuilder.should(QueryBuilders.wildcardQuery("nickName","*"+keyword+"*"));
        boolQueryBuilder.should(QueryBuilders.wildcardQuery("uniqueId","*"+keyword+"*"));
        searchSourceBuilder.sort("score", SortOrder.DESC);
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);

        try{
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            val hits = searchResponse.getHits().getHits();

            for (SearchHit hit : hits) {
                val map = JsonUtil.jsonParse(Map.class,hit.getSourceAsString());
                SearchDataResponse searchDataResponse = new SearchDataResponse();
                searchDataResponse.setAvatar(map.get("avatar168").toString().replace("sign-sg", "amd-va").replace("sign-va", "amd-va").replace("webp", "jpeg"));
                searchDataResponse.setCustomVerify("");
                searchDataResponse.setEnterpriseVerifyReason("");
                searchDataResponse.setNickname(map.get("nickName").toString());
                searchDataResponse.setRegion(map.get("region").toString());
                searchDataResponse.setUid(Long.parseLong(map.get("uid").toString()));
                searchDataResponse.setUniqueId(map.get("uniqueId").toString());
                TBlogger b = getBlogger(userId,searchDataResponse.getUid());
                if(null != b){
                    searchDataResponse.setAdded(true);
                }
                searchDataResponses.add(searchDataResponse);
            }
        }catch (Exception e){
            log.error("search blogger by es error!",e);
        }
        return searchDataResponses;
    }

    /**
     * 获取组下的播主列表信息及统计信息(总数据)
     * @param groupId
     * @param userId
     */
    public List<BloggerRecordResponse> getBloggerTotalListByGroup(long groupId,long userId){
        //结果集
        List<BloggerRecordResponse> bloggerRecordResponses;
        //统计
        BloggerRecordResponse total = new BloggerRecordResponse();
        //判断是否是查询所有
        if(0 == groupId){
            //所有的
            bloggerRecordResponses = tBloggerRepository.findBloggersByUserIdOrderByBloggerSortDesc(userId,MY_TIKTOKER_MAX_COUNT);
        }else {
            //有分组的
            bloggerRecordResponses = tGroupBloggerRepository.findBloggersByGroupIdAndUserIdOrderByBloggerSortDesc(userId, groupId,MY_TIKTOKER_MAX_COUNT);
        }

        //添加汇总统计
        if(bloggerRecordResponses.size() > 0){
            bloggerRecordResponses.forEach(bloggerRecordResponse -> {
                total.setFollowerCount(total.getFollowerCount() + bloggerRecordResponse.getFollowerCount());
                total.setLikeCount(total.getLikeCount() + bloggerRecordResponse.getLikeCount());
                total.setPostsCount(total.getPostsCount() + bloggerRecordResponse.getPostsCount());
            });
        }
        bloggerRecordResponses.add(total);
        return bloggerRecordResponses;
    }

    /**
     * 获取组下的播主列表信息及统计信息(总数据)的导出数据集
     * @param groupId
     * @param userId
     */
    public List<Map<String,Object>> getExportBloggerTotalListData(long groupId,long userId){
        //获取组下的播主列表信息及统计信息(总数据)
        val bloggerListByGroup = getBloggerTotalListByGroup(groupId,userId);
        //封装导出excel的数据集
        List<Map<String,Object>> rows = new ArrayList<>();
        bloggerListByGroup.forEach( bloggerRecordResponse -> {
            Map<String,Object> row = new LinkedHashMap<>();
            // 0为 统计数据
            if(bloggerRecordResponse.getUid() == 0){
                row.put(EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME[0],"Total");
                row.put(EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME[1],"");
            }else{
                row.put(EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME[0],bloggerRecordResponse.getNickname());
                row.put(EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME[1],bloggerRecordResponse.getUniqueId());
            }
            row.put(EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME[2],bloggerRecordResponse.getScore());
            row.put(EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME[3],bloggerRecordResponse.getFollowerCount());
            row.put(EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME[4],bloggerRecordResponse.getLikeCount());
            row.put(EXPORT_MY_TIKTOKER_TOTAL_COLUMN_NAME[5],bloggerRecordResponse.getPostsCount());
            rows.add(row);
        });
        return rows;
    }
}
